package com.jy.api.service.impl;

import com.jy.api.dao.*;
import com.jy.api.domain.*;
import com.jy.api.enums.InstanceEnum;
import com.jy.api.enums.StoreLevel;
import com.jy.api.exception.MyException;
import com.jy.api.service.CouponInstanceService;
import com.jy.api.signUpReq.clerk.CouponInstanceSignUpReq;
import com.jy.api.signUpReq.pos.PaymentSignUpReq;
import com.jy.api.util.MyDateUtils;
import com.jy.api.util.WechatUtil;
import com.jy.api.vo.admin.coupon.CouponInstanceDetailsVo;
import com.jy.api.vo.pos.coupon.CouponInstanceVo;
import com.jy.api.wechat.service.Gzh1WxService;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateData;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.security.Principal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Created by lihu on 2017/11/17.
 */
@Slf4j
@Service
public class CouponInstanceServiceImpl implements CouponInstanceService {

    @Value("${wechat.template.cardCoupons}")
    private String cardCoupons;

    @Autowired
    private Gzh1WxService wxService;

    @Autowired
    CouponInstanceDao couponInstanceDao;

    @Autowired
    CouponDao couponDao;

    @Autowired
    MemberDao memberDao;

    @Autowired
    EmployeeDao employeeDao;

    @Autowired
    private CouponCensusDao censusDao;


    @Autowired
    StoreDao storeDao;
    @Autowired
    private VerifiedTransactionDao transactionDao;

    @Override
    @Transactional
    public String addCouponInstance(CouponInstanceSignUpReq instanceSignUpReq, Principal principal) throws Exception {

        Coupon coupon = couponDao.findOne(instanceSignUpReq.getCouponId());
        if (coupon == null) {
            throw new MyException("发放失败！优惠卷信息有误！");
        }

        Store store = storeDao.findOne(coupon.getStoreId());
        if (store.getLevel() != StoreLevel.THREE) {
            throw new MyException("店铺等级不足！请升级店铺！");
        }

        if (!coupon.isEnabled()) {
            throw new MyException("发放失败！优惠卷已删除！");
        }

        Employee employee = employeeDao.findByStoreIdAndUsernameAndEnabled(coupon.getStoreId(),
                principal.getName(), true);
        if (employee == null) {
            throw new MyException("发放失败！未找到对应店铺信息！");
        }

        CouponInstance couponInstance = new CouponInstance();
        //初始化优惠卷发放数据
        couponInstance.addCouponInstance(coupon, employee);
        couponInstanceDao.save(couponInstance);
        return couponInstance.getId();
    }


    @Override
    public CouponInstance checkCouponInstance(String code, String id) {
        CouponInstance couponInstance = null;
        if (StringUtils.isNoneBlank(code)) {
            couponInstance = couponInstanceDao.findByCode(code);
        }

        if (couponInstance == null) {
            throw new MyException("优惠券使用失败！优惠卷信息有误！");
        }

        if (couponInstance.getStauts() == CouponInstanceStatus.VERIFIED) {
            throw new MyException("优惠券使用失败！优惠卷已使用！");
        }

        if (couponInstance.getEndTime().getTime() < new Date().getTime()) {
            throw new MyException("优惠券使用失败！优惠卷已过期！");
        }
//        //检查优惠卷 是否正在使用
//        Payment payment = paymentDao.findByCouponInstanceCode(couponInstance.getCode());
//        if (payment != null) {
//            throw new MyException("优惠卷使用失败！优惠卷正在使用中！");
//        }
        return couponInstance;
    }

    @Override
    public void writeOffCouponInstance(Order order, PaymentSignUpReq paymentSignUpReq) {
        log.info("订单号{},进入优惠券核销开始{}",paymentSignUpReq.getOrderId(),paymentSignUpReq);
        if (null!=paymentSignUpReq.getCoupon()){
            for (PaymentSignUpReq.coupon coupon : paymentSignUpReq.getCoupon()) {
                CouponInstance couponInstance = couponInstanceDao.findByCode(coupon.getCouponInstanceCode());
                log.info("订单号{},优惠券{}",order.getId(),couponInstance);
                if (couponInstance != null) {
                    if (couponInstance.getStauts() .equals(CouponInstanceStatus.VERIFIED) ) {
                        throw new MyException("支付失败！该优惠卷已被使用");
                    }
                    couponInstance.setValidateTime(new Date());
                    couponInstance.setStauts(CouponInstanceStatus.VERIFIED);
                    couponInstance.setOrderId(order.getId());
                    Coupon one = couponDao.findOne(couponInstance.getCouponId());
                    VerifiedTransaction transaction = new VerifiedTransaction(order, couponInstance, one);
                    couponInstanceDao.save(couponInstance);
                    transactionDao.save(transaction);
                    log.info("订单号{},保存后的优惠券{}",order.getId(),couponInstance);
                }
            }
        }
    }

    @Override
    public void writeOffCouponInstanceByOrderId(Order order) {
         CouponInstance  couponInstance =couponInstanceDao.findByOrderId(order.getId());
         log.info("订单号{},优惠券{}",order.getId(),couponInstance);
         if (couponInstance!=null){
             couponInstance.setValidateTime(new Date());
             couponInstance.setStauts(CouponInstanceStatus.VERIFIED);
             couponInstance.setOrderId(order.getId());
             Coupon one = couponDao.findOne(couponInstance.getCouponId());
             VerifiedTransaction transaction = new VerifiedTransaction(order, couponInstance, one);
             couponInstanceDao.save(couponInstance);
             transactionDao.save(transaction);
             log.info("订单号{},保存后的优惠券{}",order.getId(),couponInstance);
         }
    }

    @Override
    public CouponInstanceVo getMemberStoreCouponInstance(String memberId, String storeId, Pageable pageable) {
        List<CouponStatus> statuses = new ArrayList<>();
        statuses.add(CouponStatus.ING);
        statuses.add(CouponStatus.STOP);
        List<Coupon> content = couponDao.findByStoreIdAndStatusIn(storeId,statuses);
        List<String>  couponId= new ArrayList<>();
        for (Coupon coupon : content) {
            couponId.add(coupon.getId());
        }
        Page<CouponInstance> couponInstances = couponInstanceDao.findListByOwnerIdAndStoreIdAndStautsAndEndTimeAfterAndCouponIdIn(memberId,
                storeId, CouponInstanceStatus.NORMAL, new Date(), couponId,pageable);
        return getCouponInstanceVo(couponInstances);
    }

    @Override
    public CouponInstanceVo getMemberStatusCouponInstance(String memberId, CouponInstanceStatus stauts, String
            storeId, Pageable pageable) {


        couponInstanceDao.updateUserCouponStatus(memberId,storeId,new Date());
        Page<CouponInstance> couponInstances = null;
        List<CouponInstanceStatus> list = new ArrayList<>();
        list.add(CouponInstanceStatus.CREATED);
        list.add(CouponInstanceStatus.NORMAL);
        List<CouponStatus> statuses = new ArrayList<>();
        statuses.add(CouponStatus.ING);
        statuses.add(CouponStatus.STOP);
        if (StringUtils.isBlank(storeId)) {
            List<Coupon> content = couponDao.findByStatusIn(statuses);
            List<String>  couponId= new ArrayList<>();
            for (Coupon coupon : content) {
                couponId.add(coupon.getId());
            }
            switch (stauts){
                case NORMAL:
                    couponInstances = couponInstanceDao.findListByOwnerIdAndStautsInAndEndTimeAfterAndCouponIdIn(memberId, list, new Date(),couponId, pageable);
                    break;
                case VERIFIED:
                    couponInstances = couponInstanceDao.findListByOwnerIdAndStautsAndCouponIdInOrderByValidateTimeDesc(memberId,stauts,couponId,pageable);
                    break;
                case EXPIRED:
                    couponInstances = couponInstanceDao.findListByOwnerIdAndStautsAndCouponIdInOrderByEndTimeDesc(memberId,stauts,couponId,pageable);
                    break;
            }
        } else {
            List<Coupon> content = couponDao.findByStoreIdAndStatusIn(storeId, statuses);
            List<String>  couponId= new ArrayList<>();
            for (Coupon coupon : content) {
                couponId.add(coupon.getId());
            }
            switch (stauts){
                case NORMAL:
                    couponInstances = couponInstanceDao.findListByOwnerIdAndStoreIdAndStautsInAndEndTimeAfterAndCouponIdIn(memberId,storeId, list, new Date(),couponId, pageable);
                    break;
                case VERIFIED:
                    couponInstances = couponInstanceDao.findListByOwnerIdAndStoreIdAndStautsAndCouponIdInOrderByValidateTimeDesc(memberId,storeId,stauts,couponId,pageable);
                    break;
                case EXPIRED:
                    couponInstances = couponInstanceDao.findListByOwnerIdAndStoreIdAndStautsAndCouponIdInOrderByEndTimeDesc(memberId,storeId,stauts,couponId,pageable);
                    break;
            }
        }
        return getCouponInstanceVo(couponInstances);
    }


    @Override
    public List<CountClickAndShareRes> getCouponInstanceTotal(String storeId, String type, String begin, String end, String time, Pageable pageable) {
        Date startDate = null;
        Date endDate = null;
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        simpleDateFormat.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        sdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        List<CountClickAndShareRes> finRes = new ArrayList<>();
        try {
            if (StringUtils.equals(type, "DAY")) {
                startDate = MyDateUtils.getEarliest(sdf.parse(time));
                endDate = MyDateUtils.getLastest(sdf.parse(time));
            } else {
                startDate = simpleDateFormat.parse(begin);
                endDate = simpleDateFormat.parse(end);
            }
        } catch (ParseException e) {
            e.printStackTrace();
        }
        //查总的
        List<Coupon> coupons = couponDao.findListByStoreIdAndEnabled(storeId, true);
        List<String> strings = new ArrayList<>();
        for (Coupon c : coupons) {
            strings.add(c.getId());
            CountClickAndShareRes res = new CountClickAndShareRes(c.getTitle(), c.getId());
            finRes.add(res);
        }
        List<CouponInstance> couponInstances = couponInstanceDao.findByCouponIdInAndAddTimeBetween(strings, startDate, endDate);
        List<CouponCensus> couponCensuses = censusDao.findByCouponIdInAndAddTimeBetween(strings, startDate, endDate);
        if (couponInstances.size() > 0) {
            for (CountClickAndShareRes res : finRes) {
                for (CouponInstance c : couponInstances) {
                    if (c.getCouponId().equals(res.getCouponId())) {
                        if (c.getStauts().equals(CouponInstanceStatus.NORMAL)) {
                            res.setGiveTotalCount(res.getGiveTotalCount() + 1);
                        }
                        if (c.getStauts().equals(CouponInstanceStatus.VERIFIED)) {
                            res.setVerTotalCount(res.getVerTotalCount() + 1);
                        }
                        if (c.getStauts().equals(CouponInstanceStatus.NORMAL) && c.getCreatorName().equals("分享领取")) {
                            res.setShareGiveCount(res.getShareGiveCount() + 1);
                        }
                        if (c.getStauts().equals(CouponInstanceStatus.VERIFIED) && c.getCreatorName().equals("分享领取")) {
                            res.setVerShareCount(res.getVerShareCount() + 1);
                        }
                    }
                }

            }
        }
        if (couponCensuses.size() > 0) {
            for (CountClickAndShareRes res : finRes) {
                for (CouponCensus c : couponCensuses) {
                    if (c.getCouponId().equals(res.getCouponId())) {
                        res.setClickCount(res.getClickCount() + c.getClickCount());
                        res.setShareCount(res.getShareCount() + c.getShareCount());
                    }
                }
            }
        }
        return finRes;
    }

    /**
     * 查询优惠卷当天统计信息
     *
     * @param storeId
     * @return
     */
    private Map<String, List<Object[]>> getAllDay(String storeId) {
        Date from = MyDateUtils.getEarliest(new Date());
        Date end = MyDateUtils.getLastest(new Date());
        List<Object[]> objects = couponInstanceDao.queryCouponCount(storeId, from, end);
        Map<String, List<Object[]>> map = new HashMap<>();
        for (Object[] objects1 : objects) {
            if (map.get(objects1[0].toString()) == null) {
                List<Object[]> list = new ArrayList<>();
                list.add(objects1);
                map.put(objects1[0].toString(), list);
            } else {
                map.get(objects1[0].toString()).add(objects1);
            }
        }
        return map;
    }

    /**
     * 查询所有优惠卷信息
     *
     * @param storeId
     * @return
     */
    private Map<String, List<Object[]>> getAll(String storeId) {
        List<Object[]> objects = couponInstanceDao.queryCouponCount(storeId);
        Map<String, List<Object[]>> map = new HashMap<>();
        for (Object[] objects1 : objects) {
            if (map.get(objects1[0].toString()) == null) {
                List<Object[]> list = new ArrayList<>();
                list.add(objects1);
                map.put(objects1[0].toString(), list);
            } else {
                map.get(objects1[0].toString()).add(objects1);
            }
        }
        return map;
    }

    @Override
    public Page<CouponInstance> getvalidate(String storeId, Pageable pageable) {
        return couponInstanceDao.findListByStoreIdAndStautsOrderByValidateTimeDesc(storeId, CouponInstanceStatus.VERIFIED, pageable);
    }

    @Override
    public CouponInstanceDetailsVo getCouponInstanceDetails(String id) {
        CouponInstance couponInstance = couponInstanceDao.findOne(id);
        if (couponInstance == null) {
            throw new MyException("优惠卷信息不存在！");
        }
        Coupon coupon = couponDao.findOne(couponInstance.getCouponId());
        if (coupon == null) {
            throw new MyException("优惠卷信息不存在！");
        }
        Store store = storeDao.findOne(couponInstance.getStoreId());
        CouponInstanceDetailsVo couponInstanceDetailsVo = new CouponInstanceDetailsVo(store.getName(), store.getAddr());
        BeanUtils.copyProperties(couponInstance, couponInstanceDetailsVo);
        BeanUtils.copyProperties(coupon, couponInstanceDetailsVo);
        return couponInstanceDetailsVo;
    }

    @Override
    public void addCouponInstance(Coupon coupon, String memberId, String creatorId, String creatorName) throws Exception{

        Member member = memberDao.findOne(memberId);
        if (member == null) {
            log.error("member is null:memberId:{}", member);
        } else {
            CouponInstance couponInstance = new CouponInstance();
            //初始化优惠卷发放数据
            couponInstance.addCouponInstance(coupon, member, creatorId, creatorName);
            couponInstanceDao.save(couponInstance);
            //微信推送
            sendWechat(coupon, member, couponInstance.getId());
        }
    }

    @Override
    public InstanceEnum checkMemberCouponAuth(String openId, String couponInstanceId) {
        CouponInstance instance = couponInstanceDao.findOne(couponInstanceId);
        if (instance == null) {
            return InstanceEnum.NON;
        }

        if (instance.getEndTime().getTime() <= new Date().getTime()) {
            return InstanceEnum.OVERDUE;
        }

        /**
         * 同类可分享优惠卷只能 通过分享领取一张
         */
        List<CouponInstance> instances = couponInstanceDao.findByOpenIdAndCouponIdAndRefCouponCodeNotNull(
                openId, instance.getCouponId());
        if (instances.size() == 0) {
            return InstanceEnum.NORMAL;
        } else {
            return InstanceEnum.RECEIVE;
        }

    }

    @Async
    public void sendWechat(Coupon coupon, Member member, String couponInstanId) {
        try {
            WxMpTemplateMessage templateMessage = WxMpTemplateMessage.builder().data(setCardCouponss(coupon, member)).templateId(cardCoupons).toUser(member.getOpenId()).url(WechatUtil.COUPON_DETAILS.replace("COUPON_INSTAN_ID", couponInstanId)).build();

            this.wxService.getTemplateMsgService().sendTemplateMsg(templateMessage);
        } catch (Exception ex) {
            log.error("sendCardCoupons is error:{}", ex);
        }

    }

    private List<WxMpTemplateData> setCardCouponss(Coupon coupon, Member member) {
        Store store = storeDao.findOne(coupon.getStoreId());
        String first = "您好！你的优惠券领取成功！\n店铺名称：" + store.getName() + "\n名称：" + coupon.getTitle();
        String keyword3 = MyDateUtils.getDateFormatDd(new Date(), "yyyy年MM月dd日 HH:mm") + "\n到期时间：" +
                MyDateUtils.getDateFormatDd(MyDateUtils.increaseDate(new Date(), coupon.getExpireDays()), "yyyy年MM月dd日 HH:mm");
        List<WxMpTemplateData> wxMpTemplateDataList = new ArrayList<>();
        WxMpTemplateData wxMpTemplateData1 = new WxMpTemplateData("first", first);
        WxMpTemplateData wxMpTemplateData2 = new WxMpTemplateData("keyword1", member.getMobile());
        WxMpTemplateData wxMpTemplateData3 = new WxMpTemplateData("keyword2", MyDateUtils.getDateFormatDd(new Date(), "yyyy年MM月dd日 HH:mm"));
        WxMpTemplateData wxMpTemplateData4 = new WxMpTemplateData("keyword3", keyword3);
        WxMpTemplateData wxMpTemplateData5 = new WxMpTemplateData("remark", "请在使用期内及时使用！");
        wxMpTemplateDataList.add(wxMpTemplateData1);
        wxMpTemplateDataList.add(wxMpTemplateData2);
        wxMpTemplateDataList.add(wxMpTemplateData3);
        wxMpTemplateDataList.add(wxMpTemplateData4);
        wxMpTemplateDataList.add(wxMpTemplateData5);
        return wxMpTemplateDataList;
    }


    /**
     * 优惠卷返回值信息拼接
     *
     * @param couponInstances
     * @return
     */

    private CouponInstanceVo getCouponInstanceVo(Page<CouponInstance> couponInstances) {
        List<String> couponId = couponInstances.getContent().stream().map(e ->
                e.getCouponId()
        ).collect(Collectors.toList());

        Map<String, Coupon> couponMap = couponDao.findListByIdIn(couponId).stream().collect(Collectors.toMap(
                Coupon::getId, coupon -> coupon));

        CouponInstanceVo couponInstanceVo = new CouponInstanceVo(couponInstances.getTotalPages(), couponInstances.getTotalElements());
        for (CouponInstance couponInstance : couponInstances.getContent()) {
            Coupon coupon = couponMap.get(couponInstance.getCouponId());
            if (coupon == null) {
                continue;
            }
            CouponInstanceVo.CouponInstance couponInstance1 = new CouponInstanceVo.CouponInstance();
            BeanUtils.copyProperties(coupon, couponInstance1);
            BeanUtils.copyProperties(couponInstance, couponInstance1);
            couponInstanceVo.getCouponInstances().add(couponInstance1);
        }

        return couponInstanceVo;

    }


}
